#ifndef __INC_QGIMAGE_H__
#define __INC_QGIMAGE_H__

#ifdef _MSC_VER
#pragma once
#endif

#include "qguvls.h"

//////////////////////////////////////////////////////////////////////////
// image

//
enum qgImgType
{
	QGIMG_BMP,
	QGIMG_JPG,
	QGIMG_PNG,
};

#define QGIMGF_BGRA		0x0001
#define QGIMGF_Q50		1<<16
#define QGIMGF_Q75		2<<16
#define QGIMGF_Q90		3<<16

//
class KAPI qgImage : public kObj
{
	KCH_SUBCLASS(qgImage, kObj);

private:
	qgPixelProp			_prop;
	kint				_pitch;
	kint				_width;
	kint				_height;

	bool				_rem;
	kint				_size;
	kbyte*				_data;

protected:
	qgImage() {};
	qgImage(kint width, kint height, qgColorFormat fmt) { Initialize(width, height, fmt); };
	qgImage(kint width, kint height, qgColorFormat fmt, kpointer data, kint size, bool rem = true) { Initialize(width, height, fmt, data, size, rem); };
	~qgImage() { Clean(); };

public:
	void Initialize(kint width, kint height, qgColorFormat fmt);
	void Initialize(kint width, kint height, qgColorFormat fmt, kpointer data, kint size, bool rem = true);
	void Clean();

	const qgPixelProp& GetPixelProp() { return _prop; }
	qgColorFormat GetColorFormat() { return _prop.fmt; }
	kint GetPmul() { return _prop.bpp; }
	kint GetPitch() { return _pitch; }
	kint GetWidth() { return _width; }
	kint GetHeight() { return _height; }
	kint GetSize() { return _size; }
	kbyte* GetData() { return _data; }

	kuint GetPixel(kint x, kint y);
	kuint GetPixelBox(kint x, kint y, kint fx, kint fy, kint bias);

	void SetPixel(kint x, kint y, const tpl::ColorValue& color, bool testblend = false);

	void CopyTo(qgImage* target);
	void CopyTo(qgImage* target, const tpl::Point& pos);
	void CopyToSub(qgImage* target, const tpl::Point& pos, const tpl::Rect& srect);
	void CopyToSub(qgImage* target, const tpl::Point& pos, const tpl::Rect& srect, const tpl::Rect& clip);
	void CopyToAlpha(qgImage* target, const tpl::ColorValue& cc, const tpl::Point& pos, const tpl::Rect& srect);
	void CopyToAlpha(qgImage* target, const tpl::ColorValue& cc, const tpl::Point& pos, const tpl::Rect& srect, const tpl::Rect& clip);
	void CopyToScale(qgImage* target);
	void CopyToScaleFilter(qgImage* target, kint bias, bool blend = false);
	void CopyToScaleRaw(kpointer data, kint width, kint height, qgColorFormat fmt, kint pitch);
	void Fill(const tpl::ColorValue& cc);

	bool SaveRaw(const char* filename);
};


//////////////////////////////////////////////////////////////////////////
// blit

// 
enum qgBlitOp
{
	QG_BLITOP_NONE,
	QG_BLITOP_COLOR,
	QG_BLITOP_ALPHA_COLOR,
	QG_BLITOP_TEX,
	QG_BLITOP_TEX_ALPHA,
	QG_BLITOP_TEX_ALPHA_COLOR,
};

//
enum qgClipBound // [flag]
{
	QG_CLIPBOUND_NONE = 0,
	QG_CLIPBOUND_LEFT = 1,
	QG_CLIPBOUND_TOP = 2,
	QG_CLIPBOUND_RIGHT = 4,
	QG_CLIPBOUND_BOTTOM = 8,
};

//
class KAPI qgBlitImage
{
	KCH_SELF(qgBlitImage);
	KCH_SEAL(qgBlitImage);

public:
	static bool Blit(qgBlitOp op, qgImage* dst, const tpl::Rect* drect, const tpl::Point& dpos, qgImage* src, const tpl::Rect* srect, const tpl::ColorValue& argb);
	static bool StrechBlit(qgBlitOp op, qgImage* dst, const tpl::Rect* drect, qgImage* src, const tpl::Rect* srect, const tpl::ColorValue& argb);

	static void DrawRect(qgImage* img, const tpl::Rect& rt, const tpl::ColorValue& cc);
	static void DrawLine(qgImage* img, const tpl::Point& start, const tpl::Point& end, const tpl::ColorValue& cc);
};

// 
class KAPI qgBlitWork
{
	KCH_SELF(qgBlitWork);
	KCH_SEAL(qgBlitWork);

public:
	static void ColorConvert(kconstpointer sp, qgColorFormat sf, kint sn, kpointer dp, qgColorFormat df);
	static qgClipBound GetClip(const tpl::Rect& r, const tpl::Point& p);
	static tpl::Rect BuildClip(const tpl::Rect* clip, qgImage* img, bool passnative);
	static tpl::Rect MakeClip(qgImage* img);
	static kint ClipLine(const tpl::Rect& clip, tpl::Point* p0, tpl::Point* p1, const tpl::Point& in0, const tpl::Point& in1);
	static kuint ExtractAlpha(kuint c);
	static kuint PackAlpha(kuint c);
	static kuint PixelLerp(kuint s, kuint v);
	static kuint PixelBlend(kuint c2, kuint c1, kuint alpha);
	static kuint PixelInvBlend(kuint c2, kuint c1);
	static kushort PixelBlend16(kushort c2, kuint c1, kushort alpha);
};


//////////////////////////////////////////////////////////////////////////
// convert

// color convert & manufact
class qgCcmWork
{
	KCH_SELF(qgCcmWork);
	KCH_SEAL(qgCcmWork);

public:
	//
	static kushort TRN_RGB16_RGBA16(kushort color)
	{
		return 0x8000 | (((color & 0xFFC0) >> 1) | (color & 0x1F));
	}

	static kuint TRN_RGB16_RGBA32(kushort color)
	{
		return 0xFF000000 |
			((color & 0xF800) << 8) | ((color & 0x07E0) << 5) | ((color & 0x001F) << 3);
	}

	static kuint TRN_RGB16_BGRA32(kushort color)
	{
		return 0xFF000000 |
			((color & 0xF800) >> 8) | ((color & 0x07E0) << 5) | ((color & 0x001F) << 19);
	}

	//
	static kushort TRN_RGBA16_RGB16(kushort color)
	{
		return ((color & 0x7FE0) << 1) | (color & 0x1F);
	}

	static kuint TRN_RGBA16_RGBA32(kushort color)
	{
		return (((-((kint)color & 0x00008000) >> (kint)31) & 0xFF000000) |
			((color & 0x00007C00) << 9) | ((color & 0x00007000) << 4) |
			((color & 0x000003E0) << 6) | ((color & 0x00000380) << 1) |
			((color & 0x0000001F) << 3) | ((color & 0x0000001C) >> 2));
	}

	static kuint TRN_RGBA16_BGRA32(kushort color)
	{
		k_halt_impl("qgCcmWork");
		return 0;
	}

	//
	static kushort TRN_RGB32_RGB16(kuint color)
	{
		return (kushort)(
			((color & 0x00F80000) >> 8) |
			((color & 0x0000FC00) >> 5) |
			((color & 0x000000F8) >> 3));
	}

	static kushort TRN_RGB32_RGBA16(kuint color)
	{
		return (kushort)(0x8000 |
			((color & 0x00F80000) >> 9) |
			((color & 0x0000F800) >> 6) |
			((color & 0x000000F8) >> 3));
	}

	static kuint TRN_RGB32_BGRA32(kuint color)
	{
		kvint& v = (kvint&)color;
		return K_MAKECOLOR(0xFF, v.b.c, v.b.b, v.b.a);
	}

	//
	static kushort TRN_RGBA32_RGB16(kuint color)
	{
		return (kushort)(
			((color & 0x00F80000) >> 8) |
			((color & 0x0000FC00) >> 5) |
			((color & 0x000000F8) >> 3));
	}

	static kushort TRN_RGBA32_RGBA16(kuint color)
	{
		return (kushort)(
			((color & 0x80000000) >> 16) |
			((color & 0x00F80000) >> 9) |
			((color & 0x0000F800) >> 6) |
			((color & 0x000000F8) >> 3));
	}

	static kuint TRN_RGBA32_BGRA32(kuint color)
	{
		kvint v = (kvint&)color;
#if 0
		return K_MAKECOLOR(v.b.d, v.b.c, v.b.b, v.b.a);
#else
		return K_MAKECOLOR(v.b.d, v.b.a, v.b.b, v.b.c);
#endif
	}

	//
	static kushort TRN_BGRA32_RGB16(kuint color)
	{
		return (kushort)(
			((color & 0x000000F8) << 8) |
			((color & 0x0000FC00) >> 5) |
			((color & 0x00F80000) >> 19));
	}

	static kushort TRN_BGRA32_RGBA16(kuint color)
	{
		return (kushort)(
			((color & 0x80000000) >> 16) |
			((color & 0x000000F8) << 9) |
			((color & 0x0000F800) >> 6) |
			((color & 0x00F80000) >> 19));
	}

	static kuint TRN_BGRA32_RGBA32(kuint color)
	{
		kvint v = (kvint&)color;
		return K_MAKECOLOR(v.b.d, v.b.a, v.b.b, v.b.c);
	}

	//
	static kuint GET_RGBA16_A(kushort color)
	{
		return (color >> 15) & 0x1;
	}

	static kuint GET_RGBA16_R(kushort color)
	{
		return (color >> 10) & 0x1F;
	}

	static kuint GET_RGBA16_G(kushort color)
	{
		return (color >> 5) & 0x1F;
	}

	static kuint GET_RGBA16_B(kushort color)
	{
		return color & 0x1F;
	}

	// WARNING: the 'pitch' is not byte length. depend on type of 'out'
	KAPI static void COPY_1_16(kint width, kint height, const kbyte* in, int linepad, kushort* out, kint pitch, bool flip);
	KAPI static void COPY_1_32(kint width, kint height, const kbyte* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_4_16(kint width, kint height, const kbyte* in, int linepad, kushort* out, kint pitch, const kint* palette, bool flip);
	KAPI static void COPY_8_16(kint width, kint height, const kbyte* in, int linepad, kshort* out, kint pitch, const kint* palette, bool flip);
	KAPI static void COPY_16_16(kint width, kint height, const kshort* in, int linepad, kshort* out, kint pitch, bool flip);
	KAPI static void COPY_16_32(kint width, kint height, const kshort* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_24_32(kint width, kint height, const kbyte* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_32_32(kint width, kint height, const kint* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_BGR_4_32(kint width, kint height, const kbyte* in, int linepad, kint* out, kint pitch, const kint* palette, bool flip);
	KAPI static void COPY_BGR_8_32(kint width, kint height, const kbyte* in, int linepad, kint* out, kint pitch, const kint* palette, bool flip);
	KAPI static void COPY_BGR_16_32(kint width, kint height, const kshort* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_BGR_24_32(kint width, kint height, const kbyte* in, int linepad, kint* out, kint pitch, bool flip);
	KAPI static void COPY_BGR_32_32(kint width, kint height, const kint* in, int linepad, kint* out, kint pitch, bool flip);
};

#endif	// __INC_QGIMAGE_H__
